package org.zebias.udpnettydemo.server;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFactory;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.NetUtil;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

/**
 * @ClassName UdpServer
 * @Description UDP的服务端
 * @Author zebias
 * @Date 2021/3/1 16:48
 * @Version 1.0
 **/
public class UdpServer {

    // 单播
    public void runSingle(int port) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 通过NioDatagramChannel创建Channel,并设置Socket参数支持广播
        // UDP不需要建立连接，需要为ChannelPipeline 设置Handler
        Bootstrap b = new Bootstrap();
        try {
            b.group(bossGroup)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new UdpServerHandler());
            b.bind(port).sync().channel().closeFuture().await();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
        }
    }

    public UdpServer() {
    }

    // 组播
    private InetSocketAddress groupAddrss;
    public UdpServer(InetSocketAddress groupAddrss){
        this.groupAddrss = groupAddrss;
    }

    public void runMulticast(String netCard) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 通过NioDatagramChannel创建Channel,并设置Socket参数支持广播
        // UDP不需要建立连接，需要为ChannelPipeline 设置Handler
        Bootstrap b = new Bootstrap();
        try {
//            NetworkInterface ni = NetworkInterface.getByName("eth2");
            NetworkInterface ni = netCard == null?NetUtil.LOOPBACK_IF:NetworkInterface.getByName(netCard);
//            NetworkInterface ni = NetUtil.LOOPBACK_IF;
            Enumeration<InetAddress> addresses = ni.getInetAddresses();
            InetAddress localAddress = null;
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (address instanceof Inet4Address){
                    localAddress = address;
                }
            }
            b.group(bossGroup)
                    .channel(NioDatagramChannel.class)
//                    .channelFactory(() -> new NioDatagramChannel(InternetProtocolFamily.IPv4))
                    .localAddress(localAddress,groupAddrss.getPort())
                    .option(ChannelOption.IP_MULTICAST_IF, ni)
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .handler(new UdpServerHandler());
            NioDatagramChannel channel = (NioDatagramChannel) b.bind(groupAddrss.getPort()).sync().channel();
            // 加入组播
            channel.joinGroup(groupAddrss,ni).sync();
            // 关闭Channel
            channel.closeFuture().await();
            // 离开组
//            channel.leaveGroup(groupAddrss,ni).sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
        }
    }

    // 广播
    public void runBroadCast() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 通过NioDatagramChannel创建Channel,并设置Socket参数支持广播
        // UDP不需要建立连接，需要为ChannelPipeline 设置Handler
        Bootstrap b = new Bootstrap();
        try {
            b.group(bossGroup)
                    .channel(NioDatagramChannel.class)
                    .option(ChannelOption.SO_BROADCAST, true)
                    .handler(new UdpServerHandler());
            b.bind(groupAddrss.getPort()).sync().channel().closeFuture().await();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        // 单播
        //new UdpServer().runSingle(8888);
        // 组播
//        System.setProperty("java.net.preferIPv4Stack", "true");
//        new UdpServer(new InetSocketAddress("224.2.1.1",9000)).runMulticast("eth2");

        // 广播
        new UdpServer(new InetSocketAddress(7686)).runBroadCast();
    }
}
